# 体素下采样：对比验证

import open3d as o3d
import numpy as np

ply_point_cloud = o3d.data.PLYPointCloud()
pcd = o3d.io.read_point_cloud(ply_point_cloud.path)
print(pcd)
# print(np.asarray(pcd.points))

print("使用体素大小为 0.05 的体素来下采样点云")
downpcd = pcd.voxel_down_sample(voxel_size = 0.05)

# 方法一：直接看点数
# print(downpcd)
# o3d.visualization.draw_geometries([downpcd],
#                                   zoom=0.3412,
#                                   front=[0.4257, -0.2125, -0.8795],
#                                   lookat=[2.6172, 2.0475, 1.532],
#                                   up=[-0.0694, -0.9768, 0.2024])


# 方法二：显示在同一张图片里
# 新介绍一个PointCloud里的方法 paint_uniform_color 用于给点云设置统一的RGB颜色 元素范围[0,1]
# pcd.paint_uniform_color([1,0,0])      # 原始点云设置成红色
# downpcd.paint_uniform_color([0,1,0])  # 体素下采样后的数据设置成绿色
# # 同时显示两个点云
# o3d.visualization.draw_geometries([pcd,downpcd],
#                                   zoom=0.3412,
#                                   front=[0.4257, -0.2125, -0.8795],
#                                   lookat=[2.6172, 2.0475, 1.532],
#                                   up=[-0.0694, -0.9768, 0.2024])



# 方法三：两个窗口一起显示
# 用的是单线程的方式，多线程很容易卡死
import time  # 在当前文件下，因为点云数据并不是很大，可以不用导入time，但是后续如果遇到体量很大的点云数据，建议是一定要导入，不然CPU占比太大，系统容易卡

# 自定义“创建并配置可视化窗口”的函数
# 介绍几个新的函数和方法：
#   1.visualization.Visualizer()函数
#      是 Open3D 中负责自定义可视化流程的核心类。它不像 draw_geometries 那样 “一键显示”，而是允许你手动控制 “窗口创建、几何体添加、视角调整、非阻塞更新” 等每一个步骤。
#   2.create_window()方法
#      属于visualization.Visualizer 类的方法。
#      参数 window_name：指定窗口的标题
#      参数 width/height：设置窗口的宽、高，控制显示区域的大小
#   3.add_geometry()方法
#      是 Visualizer 类的方法，作用是将点云等几何体添加到可视化场景中
#   4.get_view_control()方法
#      是 Visualizer 类的方法，返回 ViewControl 类的实例，所有控制相机视角的操作都要通过它
#   5.ctr.set_front(...)、ctr.set_lookat(...)、ctr.set_up(...)、ctr.set_zoom(...)
#      ViewControl 类的方法，用于精确调整相机的朝向、聚焦点、上方向和缩放比例
#   6.poll_events()方法
#      属于visualization.Visualizer 类的方法，用于检测窗口的交互事件
#   7.update_renderer() 方法
#      属于Visualizer 类的方法，用于更新窗口的渲染画面
#   8.destroy_window() 方法
#      Visualizer 类的方法，用于主动销毁窗口
def setup_visualizer(pcd_to_show,window_name):
    vis = o3d.visualization.Visualizer()
    vis.create_window(window_name = window_name, width=1000, height = 800)
    vis.add_geometry(pcd_to_show)
    #配置视角，和之前的视角保持一致
    ctr = vis.get_view_control()
    ctr.set_front([0.4257, -0.2125, -0.8795])
    ctr.set_lookat([2.6172, 2.0475, 1.532])
    ctr.set_up([-0.0694, -0.9768, 0.2024])
    ctr.set_zoom(0.3412)
    return vis

# 创建两个独立的可视化窗口
vis_pcd = setup_visualizer(pcd, "原始点云")
vis_downpcd = setup_visualizer(downpcd, "下采样点云")

# try...except...finally 结构，用于异常处理与资源兜底释放
#   except KeyboardInterrupt：捕获 “用户按 Ctrl+C 强制终止程序” 的情况，避免程序直接崩溃
#   
try:
    # 标记两个窗口的运行状态，True：正在运行，False：关闭
    pcd_running = True
    downpcd_running = True
    
    # 只要有一个窗口关闭，循环就终止
    while pcd_running and downpcd_running:  
        # 处理原始点云窗口
        if pcd_running:
            # 检测窗口事件
            pcd_running = vis_pcd.poll_events()  
            # 跟新渲染
            vis_pcd.update_renderer()  
        
        # 处理下采样点云窗口
        if downpcd_running:
            # 检测窗口事件
            downpcd_running = vis_downpcd.poll_events()  
            vis_downpcd.update_renderer() 
        
        time.sleep(0.01)  # 降低CPU占用

except KeyboardInterrupt:
    pass
finally:
    # 无论哪个窗口关闭，都销毁两个窗口
    vis_pcd.destroy_window()
    vis_downpcd.destroy_window()